package mspbots.autotask.client.core.data.users;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.autotask.client.core.AbstractToolsUtil;
import mspbots.autotask.client.core.BaseSyncService;
import mspbots.autotask.client.core.client.ClientProperties;
import mspbots.autotask.client.core.client.ClientUtils;
import mspbots.autotask.common.*;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * mspbots.core.autotask.core.servicecall.UsersService
 *
 * @author <a href="https://github.com/vnobo">Alex bob</a>
 * @date Created by 2020/7/9
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class UsersServiceImpl extends AbstractToolsUtil implements BaseSyncService {

    private final String QUERY_REQUEST_PATH = "/V1.0/Resources/query";

    public Mono<JsonNode> find(Long tenantId, QueryBody queryBody, URI pageUrl) {
        return super.loadProperties(tenantId)
                .flatMap(properties -> this.findUsers(properties, queryBody, pageUrl));
    }

    public Mono<JsonNode> count(Long tenantId, QueryBody queryBody) {
        return super.loadProperties(tenantId)
                .flatMap(properties -> this.countUsers(properties, queryBody));
    }

    public Mono<JsonNode> countUsers(ClientProperties properties, QueryBody queryBody) {
        queryBody.setMaxRecords(0);
        return super.autoTaskClient.post(ClientUtils.builderRequestUrl(properties.getBaseUrl(), "/V1.0/Resources/query/count"), queryBody)
                .subscriberContext(ctx -> ctx.put("properties", properties));
    }

    @Override
    public Mono<Void> syncFast(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("USERS-SYNC");
        return this.hireDateCacheFilterUsers(properties)
                .subscriberContext(ctx -> ctx.put("resultSync", resultSync))
                .doOnNext(result -> this.syncResult(properties.getTenantId(), resultSync.getRequestId(), result))
                .then();
    }

    private void syncResult(Long tenantId, UUID id, JsonNode resultNode) {
        this.sendEntity(RabbitKeys.USERS_SYNC_QUEUE_KEY, ResultMsg.builder()
                .requestId(id).id(resultNode.get("id").longValue())
                .action("none").entity(resultNode).tenantId(tenantId)
                .syncDate(LocalDateTime.now()).build());
    }

    private Flux<JsonNode> hireDateCacheFilterUsers(ClientProperties properties) {
        String redisAnchorKey = RedisKeys.USERS_ANCHOR_REDIS_KEY_PREFIX + properties.getTenantId();
        return this.fetchUsers(properties, QueryBody.withFilter(FilterExpression.builder()
                .op("gt").field("id").value("0").build()));
//        return super.readAnchorTime(redisAnchorKey)
//                .flatMapMany(syncTime -> this.fetchUsers(properties, QueryBody.withFilter(FilterExpression.builder()
//                        .op("gt").field("id").value("0").build())))
//                .doOnNext(user -> super.recordAnchorTime(redisAnchorKey, user.get("hireDate").textValue()));
    }

    private Flux<JsonNode> fetchUsers(ClientProperties properties, QueryBody queryBody) {
        return super.autoTaskClient
                .fetch(ClientUtils.builderRequestUrl(properties.getBaseUrl(), QUERY_REQUEST_PATH), queryBody)
                .subscriberContext(ctx -> ctx.put("properties", properties));
    }

    private Mono<JsonNode> findUsers(ClientProperties properties, QueryBody queryBody, URI pageUrl) {
        if (ObjectUtils.isEmpty(pageUrl)) {
            pageUrl = ClientUtils.builderRequestUrl(properties.getBaseUrl(), QUERY_REQUEST_PATH);
        }
        return super.autoTaskClient
                .post(pageUrl, queryBody)
                .subscriberContext(ctx -> ctx.put("properties", properties));
    }


}
